﻿using DevExpress.XtraBars;
using DevExpress.XtraEditors;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using XCI.Core;
using XCI.Extensions;
using XCI.Helper;
using XCI.Service;

namespace XCI.Windows
{
    /// <summary>
    /// 图片上传控件
    /// </summary>
    [System.ComponentModel.DesignerCategory("Code")]
    public partial class ImageUploadControl : BaseUserControl
    {
        private LoadingMask loadingPanel;
        private object _editValue;
        private bool _isUpload;
        private string _currentFilePath;

        /// <summary>
        /// 初始化图片上传控件
        /// </summary>
        public ImageUploadControl()
        {
            InitializeComponent();
            openFile.Filter = "PNG文件 (*.png)|*.png|GIF文件 (*.gif)|*.gif|JPEG文件 (*.jpg;*.jpeg)|*.jpg;*.jpeg|所有图像文件 |*.bmp;*.gif;*.jpg;*.jpeg;*.png;|所有文件 |*.*";
            saveFile.Filter = "PNG文件 (*.png)|*.png|GIF文件 (*.gif)|*.gif|JPEG 文件 (*.jpg)|*.jpg|位图文件 (*.bmp)|*.bmp";
        }

        /// <summary>
        /// Bar控件
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public BarManager BarManager => barManager1;

        /// <summary>
        /// 工具条控件
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Bar ToolBar => bar1;

        /// <summary>
        ///图片控件
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public PictureEdit PictureEdit => pictureEdit1;

        /// <summary>
        /// 选择按钮
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public BarButtonItem SelectButton => btnSelect;

        /// <summary>
        /// 移除按钮
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public BarButtonItem RemoveButton => btnRemove;

        /// <summary>
        /// 上传按钮
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public BarButtonItem UploadButton => btnUpload;

        /// <summary>
        /// 导出按钮
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public BarButtonItem ExportButton => btnExport;

        /// <summary>
        /// 上传子文件夹
        /// </summary>
        [Category("XCI"), Description("上传子文件夹"), Browsable(true)]
        public virtual string UploadFolder { get; set; }

        /// <summary>
        /// 初始图片
        /// </summary>
        [Category("XCI"), Description("默认图片"), Browsable(true), DefaultValue(null)]
        public virtual Image InitImage { get; set; }

        /// <summary>
        /// 是否显示工具栏
        /// </summary>
        [Category("XCI"), Description("是否显示工具栏"), DefaultValue(true), Browsable(true)]
        public virtual bool ToolbarVisable { get; set; } = true;

        /// <summary>
        /// 选择按钮是否可见
        /// </summary>
        [Category("XCI"), Description("选择按钮是否可见"), DefaultValue(true), Browsable(true)]
        public virtual bool SelectVisible { get; set; } = true;

        /// <summary>
        /// 选择按钮文本
        /// </summary>
        [Category("XCI"), Description("选择按钮文本"), DefaultValue("选择"), Browsable(true)]
        public virtual string SelectText { get; set; } = "选择";

        /// <summary>
        /// 移除按钮是否可见
        /// </summary>
        [Category("XCI"), Description("移除按钮是否可见"), DefaultValue(true), Browsable(true)]
        public virtual bool RemoveVisible { get; set; } = true;

        /// <summary>
        /// 移除按钮文本
        /// </summary>
        [Category("XCI"), Description("移除按钮文本"), DefaultValue("移除"), Browsable(true)]
        public virtual string RemoveText { get; set; } = "移除";

        /// <summary>
        /// 上传按钮是否可见
        /// </summary>
        [Category("XCI"), Description("上传按钮是否可见"), DefaultValue(true), Browsable(true)]
        public virtual bool UploadVisible { get; set; } = true;

        /// <summary>
        /// 上传按钮文本
        /// </summary>
        [Category("XCI"), Description("上传按钮文本"), DefaultValue("上传"), Browsable(true)]
        public virtual string UploadText { get; set; } = "上传";

        /// <summary>
        /// 导出按钮是否可见
        /// </summary>
        [Category("XCI"), Description("导出按钮是否可见"), DefaultValue(true), Browsable(true)]
        public virtual bool ExportVisible { get; set; } = true;

        /// <summary>
        /// 导出按钮文本
        /// </summary>
        [Category("XCI"), Description("导出按钮文本"), DefaultValue("导出"), Browsable(true)]
        public virtual string ExportText { get; set; } = "导出";

        /// <summary>
        /// 获取或设置指定当前选定值。
        /// </summary>
        [Category("XCI"), Description("获取或设置指定当前选定值。"), Bindable(true), Browsable(false), DefaultValue(null)]
        public virtual object EditValue
        {
            get => _editValue;
            set => _ = BindImageAsync(value);
        }

        /// <summary>
        /// 当前图片
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Image CurrentImage
        {
            get
            {
                if (pictureEdit1.Image != InitImage)
                {
                    return pictureEdit1.Image;
                }

                return null;
            }
        }

        /// <summary>
        /// 是否有图片
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool HasImage => CurrentImage != null;

        /// <summary>
        /// 图片是否需要上传
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool RequiredUpload => !_isUpload && CurrentImage != null;

        /// <summary>
        /// 图片加载前事件
        /// </summary>
        [Category("XCI"), Description("图片加载前事件")]
        public event EventHandler<ImageBeforeEventArgs> BeforeLoad;

        /// <summary>
        /// 图片加载之后事件
        /// </summary>
        [Category("XCI"), Description("图片加载之后事件")]
        public event EventHandler<EventArgs> AfterLoad;

        /// <summary>
        /// 图片上传前事件
        /// </summary>
        [Category("XCI"), Description("图片上传前事件")]
        public event EventHandler<ImageBeforeEventArgs> BeforeUpload;

        /// <summary>
        /// 图片上传之后事件
        /// </summary>
        [Category("XCI"), Description("图片上传之后事件")]
        public event EventHandler<ImageUploadEventArgs> AfterUpload;

        /// <summary>
        /// 当图片加载前触发
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnBeforeLoad(ImageBeforeEventArgs e)
        {
            BeforeLoad?.Invoke(this, e);
        }

        /// <summary>
        /// 当图片加载后触发
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnAfterLoad(EventArgs e)
        {
            AfterLoad?.Invoke(this, e);
        }

        /// <summary>
        /// 当图片上传前触发
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnBeforeUpload(ImageBeforeEventArgs e)
        {
            BeforeUpload?.Invoke(this, e);
        }

        /// <summary>
        /// 当图片上传后触发
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnAfterUpload(ImageUploadEventArgs e)
        {
            AfterUpload?.Invoke(this, e);
        }

        /// <summary>
        /// 绑定图片
        /// </summary>
        /// <param name="editvalue">绑定值</param>
        public virtual async Task BindImageAsync(object editvalue)
        {
            if (editvalue.IsEmpty()) return;
            if (_editValue == editvalue) return;

            _editValue = editvalue;
            _isUpload = true;
            _currentFilePath = null;
            await LoadImageAsync(editvalue.ToString());
            SetButtonStatus();
        }

        /// <summary>
        /// 选择图片
        /// </summary>
        /// <param name="localFilePath">图片路径</param>
        protected virtual void SelectImageCore(string localFilePath)
        {
            if (!ImageHelper.IsImage(localFilePath))
            {
                MessageBoxHelper.ShowWarn("请选择有效的图片文件");
                return;
            }

            pictureEdit1.Image = null;

            _currentFilePath = localFilePath;
            _isUpload = false;
            pictureEdit1.Image = ImageHelper.LoadImage(_currentFilePath);
            SetButtonStatus();
        }

        /// <summary>
        /// 生成右键菜单
        /// </summary>
        protected virtual void BuildPopupMenuCore()
        {
            foreach (BarItem item in barManager1.Items)
            {
                //if (!(item is BarButtonItem)) continue;
                popupMenu1.ItemLinks.Add(item);
            }
        }

        /// <summary>
        /// 设置按钮状态
        /// </summary>
        protected virtual void SetButtonStatus()
        {
            btnRemove.Enabled = HasImage;
            btnUpload.Enabled = RequiredUpload;
            btnExport.Enabled = HasImage;
            btnPreview.Enabled = HasImage;
        }

        /// <summary>
        /// 加载图片
        /// </summary>
        /// <param name="path">图片路径（服务器路径）</param>
        public virtual async Task LoadImageAsync(string path)
        {
            var args = new ImageBeforeEventArgs();
            OnBeforeLoad(args);
            if (args.Cancel)
            {
                return;
            }

            await loadingPanel.ShowAsync(async () =>
            {
                var bytes = await FileUploadService.Instance.DownloadAsBytesAsync(path);
                if (bytes == null || bytes.Length == 0) return;
                
                pictureEdit1.Image = ImageHelper.FromArray(bytes);
                SetButtonStatus();
                OnAfterLoad(EventArgs.Empty);
            });
        }

        /// <summary>
        /// 选择图片
        /// </summary>
        public virtual void SelectImage()
        {
            this.openFile.FilterIndex = this.openFile.Filter.Split('|').Length / 2 - 1;
            if (this.openFile.ShowDialog() != DialogResult.OK) return;
            if (this.openFile.FileName.IsEmpty()) return;

            SelectImageCore(this.openFile.FileName);
        }

        /// <summary>
        /// 移除图片
        /// </summary>
        public virtual void RemoveImage()
        {
            if (MessageBoxHelper.ShowMessageYesNo("确定要移除当前图片吗？") != DialogResult.Yes) return;

            _editValue = null;
            _isUpload = false;
            _currentFilePath = null;
            pictureEdit1.Image = InitImage;
            SetButtonStatus();
        }

        /// <summary>
        /// 上传图片
        /// </summary>
        public virtual async Task UploadImageAsync()
        {
            var args = new ImageBeforeEventArgs();
            OnBeforeUpload(args);
            if (args.Cancel) return;
            if (!RequiredUpload) return;

            var fileInfo = new FileInfo(_currentFilePath);
            await loadingPanel.ShowAsync(async () =>
            {
                var result = await FileUploadService.Instance.UploadAsync(fileInfo.FullName, UploadFolder);
                _editValue = result.Path;
                _isUpload = true;
                SetButtonStatus();
                var ar = new ImageUploadEventArgs { FileModelInfo = result };
                OnAfterUpload(ar);
            });
        }

        /// <summary>
        /// 保存图片
        /// </summary>
        public virtual void ExportImage()
        {
            if (pictureEdit1.Image == null)
            {
                MessageBoxHelper.ShowWarn("当前没有图片");
                return;
            }

            if (EditValue.IsNotEmpty())
            {
                saveFile.FileName = Path.GetFileName(EditValue.ToStringOrEmpty());
            }
            else if (_currentFilePath.IsNotEmpty())
            {
                saveFile.FileName = Path.GetFileName(_currentFilePath);
            }

            if (this.saveFile.ShowDialog() != DialogResult.OK) return;

            try
            {
                using (var fileStream = new FileStream(this.saveFile.FileName, FileMode.Create))
                {
                    ImageFormat format;
                    switch (this.saveFile.FilterIndex)
                    {
                        case 1:
                            format = ImageFormat.Bmp;
                            break;
                        case 2:
                            format = ImageFormat.Gif;
                            break;
                        case 4:
                            format = ImageFormat.Png;
                            break;
                        default:
                            format = ImageFormat.Jpeg;
                            break;
                    }
                    pictureEdit1.Image.Save(fileStream, format);
                }
                MessageBoxHelper.ShowWarn($"导出成功,文件保存在{this.saveFile.FileName}");
            }
            catch (Exception ex)
            {
                XtraMessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }
        }

        /// <summary>
        /// 预览图片
        /// </summary>
        public virtual void PreviewImage()
        {
            if (pictureEdit1.Image == null)
            {
                //MessageBoxHelper.ShowWarn("当前没有图片");
                return;
            }
            FrmImagePreview frmImagePreview = new FrmImagePreview(pictureEdit1.Image);
            frmImagePreview.Size = WinFormHelper.GetImagePreviewSize();
            frmImagePreview.Show();
        }

        private void ImageUploadControl_Load(object sender, EventArgs e)
        {
            loadingPanel = new LoadingMask(this);
            bar1.Visible = ToolbarVisable;

            btnSelect.Caption = SelectText;
            btnSelect.Visibility = WinFormHelper.BarItemVisible(SelectVisible);

            btnRemove.Caption = RemoveText;
            btnRemove.Visibility = WinFormHelper.BarItemVisible(RemoveVisible);

            btnUpload.Caption = UploadText;
            btnUpload.Visibility = WinFormHelper.BarItemVisible(UploadVisible);

            btnExport.Caption = ExportText;
            btnExport.Visibility = WinFormHelper.BarItemVisible(ExportVisible);

            BuildPopupMenuCore();
            SetButtonStatus();

            if (pictureEdit1.Image == null && InitImage != null)
            {
                pictureEdit1.Image = InitImage;
            }
        }

        private void PictureEdit1_PopupMenuShowing(object sender, DevExpress.XtraEditors.Events.PopupMenuShowingEventArgs e)
        {
            e.Cancel = true;
            popupMenu1.ShowPopup(Control.MousePosition);
        }

        private void PictureEdit1_DoubleClick(object sender, EventArgs e)
        {
            PreviewImage();
        }

        private void BtnSelect_ItemClick(object sender, ItemClickEventArgs e)
        {
            SelectImage();
        }

        private void BtnRemove_ItemClick(object sender, ItemClickEventArgs e)
        {
            RemoveImage();
        }

        private async void BtnUpload_ItemClick(object sender, ItemClickEventArgs e)
        {
            await UploadImageAsync();
        }

        private void BtnSave_ItemClick(object sender, ItemClickEventArgs e)
        {
            ExportImage();
        }

        private void BtnPreview_ItemClick(object sender, ItemClickEventArgs e)
        {
            PreviewImage();
        }

        private void PictureEdit1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void PictureEdit1_DragDrop(object sender, DragEventArgs e)
        {
            var files = (string[])e.Data.GetData(DataFormats.FileDrop);
            if (files.Length <= 0) return;
            var filePath = files[0];
            try
            {
                SelectImageCore(filePath);
            }
            catch
            {
                MessageBoxHelper.ShowError("无效的文件");
            }
        }

    }
}
